/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ru.niir.goodfil.ui;

import org.apache.log4j.Logger;
import ru.niir.goodfil.db.Client;
import ru.niir.goodfil.db.Good;
import ru.niir.goodfil.db.Order;
import ru.niir.goodfil.db.OrderItem;
import ru.niir.goodfil.db.dic.OrderState;
import ru.niir.goodfil.exceptions.EmptyOrderException;
import ru.niir.goodfil.exceptions.OrderStateChangeException;
import ru.niir.goodfil.exceptions.ValidationException;

import java.sql.Timestamp;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static ru.niir.goodfil.utils.Utils._assertNotNull;

/**
 * Клиентская корзина.
 *
 * @author Носов А.В.
 */
public class ClientOrderItemBean extends PageBean {

    private static final Logger logger = Logger.getLogger(ClientOrderItemBean.class);
    /***/
    private Map<Long, Integer> delOrderItemCount = null;
    /**
     * Товар в заказе
     */
    private OrderItem orderItem = new OrderItem();

    /**
     * Возвращает количество удаляемого товара в заказе.
     *
     * @return
     */
    public Map<Long, Integer> getDelOrderItemCount() {
        if (delOrderItemCount == null) {
            List<OrderItem> list = getSessionBean().getOrderItems();
            delOrderItemCount = new HashMap<Long, Integer>();
            for (OrderItem o : list)
                delOrderItemCount.put(o.getGoodId(), o.getCount());

            logger.debug("delOrderItemCount size " + delOrderItemCount.size());
        }
        return delOrderItemCount;
    }

    /**
     * Устанавливает количество удаляемого товара.
     *
     * @param delOrderItemCount
     */
    public void setDelOrderItemCount(Map<Long, Integer> delOrderItemCount) {
        this.delOrderItemCount = delOrderItemCount;
    }

    /**
     * Возвращает товар в заказе.
     *
     * @return товар
     */
    public OrderItem getOrderItem() {
        return orderItem;
    }

    /**
     * Устанавливает товар в заказе.
     *
     * @param orderItem товар
     */
    public void setOrderItem(OrderItem orderItem) {
        this.orderItem = orderItem;
    }


    /**
     * -------------------------------------------------------------------------
     * ----------Работа с БД----------
     * -------------------------------------------------------------------------
     */

    /**
     * Удаление товара из заказа.
     */
    public void updateOrder() {
        try {
            int a = Integer.valueOf(String.valueOf(delOrderItemCount.get(orderItem.getGoodId())));
            Good good = gf().getGoodById(orderItem.getGoodId());
            List<OrderItem> orderItems = getSessionBean().getOrderItems();
            for (OrderItem oi : orderItems) {
                if (oi.getGoodId() == good.getId()) {
                    oi.setCount(a);
                    getSessionBean().setOrderItems(orderItems);
                    break;
                }
            }

            facesInfo("Количество товара " + good.getCode() + " " + good.getName() + " изменено");
        } catch (Exception e) {
            logger.error(e);
            e.printStackTrace();

            facesError("Не удалось изменить количество товара в заказе");
        }
    }

    /**
     * Удаление товара из корзины.
     */
    public void deleteOrderItem() {
        try {
            Good good = gf().getGoodById(orderItem.getGoodId());
            List<OrderItem> orderItems = getSessionBean().getOrderItems();
            for (OrderItem oi : orderItems) {
                if (oi.getGoodId() == good.getId()) {
                    oi.setCount(0);
                    getSessionBean().setOrderItems(orderItems);
                    break;
                }
            }

            facesInfo("Товар " + good.getCode() + " " + good.getName() + " удален из корзины");
        } catch (Exception e) {
            logger.error(e);
            e.printStackTrace();

            facesError("Не удалось удалить товар из корзины");
        }
    }

    /**
     * Комментарий, который вводится клиентом на странице оформления заказа.
     */
    public String getClientComment() {
        Order order = gf().getOrderById(getSessionBean().getSelectedOrderId());
        return order.getDeliveryInfoExt().getComment();
    }

    private String clientComment;
    
    /**
     * Комментарий, который вводится клиентом на странице оформления заказа.
     */
    public void setClientComment(String clientComment) {
        this.clientComment = clientComment;
    }

    /**
     * Заявка на оформление заказа.
     * <p/>
     * EXPERIMENTAL: Когда клиент нажимает "Оформить заказ" начинает работать механизм резервирования.
     * Механизм резервирования состоит из двух частей:
     * 1. В заказе устанавливается дата резервирования, как текущая дата + интвервал в днях, заданный системной настройкой orders.reservation.timeout.
     * Если по истечении этого срока, заказ не переходит в статус "оплачен", каждый день менеджеру высылается уведомление про просроченый заказ.
     * 2. Резервируется необходимое кол-во товара
     */
    public void issueOrder() {
        logger.debug("Pre: Order is now awaiting validation");

        if (getSessionBean().getSelectedClientId() == -1)
            facesError("Вы должны зарегистрироваться для оформления заказа");
        if (!gf().clientCanSaveOrder(getSessionBean().getSelectedClientId())) {
            facesError("Величина Вашего долга не позволяет Вам оформить заказ");
        }

        if (hasFacesErrors()) return;

        //  EXPERIMENTAL: Проверка, что все позиции заказа имеют код соответствия 1С
        {
            List<OrderItem> orderItems = gf().getOrderItemsByOrderId(getSessionBean().getSelectedOrderId());
            for (OrderItem orderItem : orderItems) {
                Good good = gf().getGoodById(orderItem.getGoodId());
                _assertNotNull(good, "В заказе присутствует несуществующий товар");

                if (good.getC1CodeIsMissing()) {
                    facesError("В заказе присутствует товар, для которого отсутствует код соответствия 1С");
                    return;
                }
            }
        }


        try {
            Client client = gf().getClientById(getSessionBean().getSelectedClientId());

            // Установка для заказа даты резервирования
            Order order = gf().getOrderById(getSessionBean().getSelectedOrderId());

            Calendar c = Calendar.getInstance();
            c.add(Calendar.DATE, gf().getInt("orders.reservation.timeout"));
            order.setReservationDate(new Timestamp(c.getTimeInMillis()));

            //  Установка комментария
            order.getDeliveryInfoExt().setComment(clientComment);
            
            gf().updateOrder(order);

            // Формирование реального резерва
            List<OrderItem> orderItems = gf().getOrderItemsByOrderId(getSessionBean().getSelectedOrderId());
            for (OrderItem orderItem : orderItems) {

                Good good = gf().getGoodById(orderItem.getGoodId());
                good.setReservedCount(good.getReservedCount() + orderItem.getCount());
                if (good.getReservedCount() > good.getCount()) {
                    good.setReservedCount(good.getReservedCount() - orderItem.getCount());
                    facesError("Недостаточное кол-во товара \"" + good.getCode() + " " + good.getName() + "\". В наличии всего: " + (good.getCount() - good.getReservedCount()));
                    return;
                }
                gf().updateGood(good);
            }

            if (client.isAllowQuickOrder()) {
                gf().setOrderState(getSessionBean().getSelectedOrderId(), OrderState.VALIDATED);
                logger.debug("Order " + getSessionBean().getSelectedOrderId() + " is now validated");
            } else {
                gf().setOrderState(getSessionBean().getSelectedOrderId(), OrderState.AWAITING_VALIDATION);
                logger.debug("Order " + getSessionBean().getSelectedOrderId() + " is now awaiting validation");
            }

            getSessionBean().refreshOrder();

            facesInfo("Заяка на оформление принята");
        } catch (EmptyOrderException eo) {
            facesError("Выполнение операций над пустым заказом не допускается");
        } catch (OrderStateChangeException e) {
            facesError(e.toString());
        } catch (ValidationException e) {
            facesError("Не удалось произвести резервирование товара");
        }
    }
}
